#ifndef SPEED_CNTR_H
#define SPEED_CNTR_H

#include "global.h"
#include "freq_table.h"

struct SpeedRampData;

typedef void (*SPEED_CALLBACK)();
typedef void (*STEP_UPDATE)();
typedef void (*PULSE_PROC)(uchar level);
typedef void (*TIMER_PROC)(ushort tick);
typedef void (*STOP_TIMER)();

typedef struct SpeedRampData
{
    uchar run_state : 3;        // What part of the speed ramp we are in.
    uchar dir : 1;              // Direction stepper motor should move.
    uchar running : 1;          // 电机正在运行
    uchar need_cleanup : 1;     // 需要运行清除函数
    uchar home_state : 1;       // 原点传感器状态
    uchar limit_state : 1;      // 限位传感器状态
    uchar hit_home : 1;         // 运行经过原点
    uchar hit_limit :1;         // 运行经过限位点
    uchar ref_changed : 1;      // 参考系坐标或速度改变
    uchar interp : 1;           // 是否使用插值算法. 如果使用插值, 不单独更新坐标.
    uchar ignore_step_left : 1; // 碰到原点时不重新计算剩余步数
    uchar output : 1;           // 端口输出值

    ushort speed_index;         // Counter used when accelerateing/decelerateing to calculate step_delay.
    ushort max_index;           // 频率表最大索引
    ushort max_ideal_index;     // 根据设定的最高速度和步数计算得出的最大速度索引
    ushort max_ref_index;       // 根据参考系计算出的最大允许索引
    long step_left;             // 电机剩余运行步数
    ulong step_count;           // Counting steps when moving.
    ulong start_time;           // 开始运行时间
    char step_offset;           // 每走一步的增量, +/-1
    long target;                // 目标坐标
    long step_correction;       // 剩余量修正值, 用于插补运动时, 经过原点后剩余步数改变的情况
    ushort first_stage_speed;   // 开始阶段低速运行的速度索引
    ushort first_stage_step;    // 开始阶段低速运行的步数
    ushort second_stage_speed;  // 结束阶段低速运行的速度索引
    ushort second_stage_step;   // 结束阶段低速运行的步数

    SPEED_CALLBACK init;        // 电机启动前调用的初始化函数
    SPEED_CALLBACK update;      // 每走一步调用的函数
    SPEED_CALLBACK cleanup;     // 停止后调用的函数
    PULSE_PROC step;            // step信号输出
    TIMER_PROC start_timer;     // 更新定时器
    STOP_TIMER stop_timer;      // 停止定时器
} SpeedRampData;

// Speed ramp states
#define MOTION_STATE_STOP       0
#define MOTION_STATE_ACCEL      1
#define MOTION_STATE_DECEL      2
#define MOTION_STATE_RUN        3

#define CCW                     0   // 反向
#define CW                      1   // 正向

extern SpeedRampData srd_x;
extern SpeedRampData srd_y;
extern SpeedRampData srd_z;

#if (PCB_VERSION == PCB_A2)
extern SpeedRampData srd_m;
#endif

ushort speed_cntr_max_index(ushort speed);
void speed_cntr_Move(SpeedRampData *srd, long step, unsigned int speed);
void speed_cntr_update(SpeedRampData *srd) reentrant;
void speed_cntr_interp(long xstep, long ystep, unsigned int speed);
void speed_cntr_interp_update();

#endif
